package com.cleanvegetable.config;

import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

/**
 * RabbitMQ配置类
 * @author cleanvegetable
 */
@Data
@Slf4j
@Configuration
@ConfigurationProperties(prefix = "spring.rabbitmq")
public class RabbitMQConfig {
    private String host;
    private int port;
    private String username;
    private String password;
    private String virtualHost = "/";
    private int connectionTimeout = 30000;
    private int requestedHeartbeat = 60;

    /**
     * 公司信息交换机
     */
    public static final String COMPANY_EXCHANGE = "company.exchange";

    /**
     * 财务系统同步队列
     */
    public static final String COMPANY_FINANCE_QUEUE = "company.finance.queue";

    /**
     * 通知队列
     */
    public static final String COMPANY_NOTIFY_QUEUE = "company.notify.queue";

    /**
     * 日志记录队列
     */
    public static final String COMPANY_LOG_QUEUE = "company.log.queue";

    /**
     * 财务系统路由键
     */
    public static final String COMPANY_FINANCE_KEY = "company.finance";

    /**
     * 通知路由键
     */
    public static final String COMPANY_NOTIFY_KEY = "company.notify";

    /**
     * 日志路由键
     */
    public static final String COMPANY_LOG_KEY = "company.log";

    /**
     * 配置RabbitMQ连接工厂
     */
    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory();
        connectionFactory.setHost(host);
        connectionFactory.setPort(port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        
        // 设置连接超时
        connectionFactory.setConnectionTimeout(connectionTimeout);
        
        // 设置心跳
        connectionFactory.setRequestedHeartBeat(requestedHeartbeat);
        
        // 设置发布确认
        connectionFactory.setPublisherConfirmType(CachingConnectionFactory.ConfirmType.CORRELATED);
        connectionFactory.setPublisherReturns(true);
        
        log.info("正在创建RabbitMQ连接工厂，host={}，port={}", host, port);
        return connectionFactory;
    }

    /**
     * 声明交换机
     */
    @Bean
    public FanoutExchange companyExchange() {
        // 使用扇形交换机，消息会广播到所有绑定的队列
        return new FanoutExchange(COMPANY_EXCHANGE, true, false);
    }

    /**
     * 声明财务系统队列
     */
    @Bean
    public Queue financeQueue() {
        return new Queue(COMPANY_FINANCE_QUEUE, true);
    }

    /**
     * 声明通知队列
     */
    @Bean
    public Queue notifyQueue() {
        return new Queue(COMPANY_NOTIFY_QUEUE, true);
    }

    /**
     * 声明日志队列
     */
    @Bean
    public Queue logQueue() {
        return new Queue(COMPANY_LOG_QUEUE, true);
    }

    /**
     * 绑定财务系统队列到交换机
     */
    @Bean
    public Binding financeBinding() {
        return BindingBuilder.bind(financeQueue()).to(companyExchange());
    }

    /**
     * 绑定通知队列到交换机
     */
    @Bean
    public Binding notifyBinding() {
        return BindingBuilder.bind(notifyQueue()).to(companyExchange());
    }

    /**
     * 绑定日志队列到交换机
     */
    @Bean
    public Binding logBinding() {
        return BindingBuilder.bind(logQueue()).to(companyExchange());
    }

    /**
     * 配置RabbitTemplate
     */
    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        // 使用Jackson2JsonMessageConverter来序列化消息
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        
        // 消息发送确认回调
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (!ack) {
                log.error("消息发送失败：correlationData={}, cause={}", correlationData, cause);
            }
        });
        
        // 消息发送失败回调
        rabbitTemplate.setReturnsCallback(returned -> {
            log.error("消息发送失败：message={}, replyCode={}, replyText={}, exchange={}, routingKey={}",
                returned.getMessage(),
                returned.getReplyCode(),
                returned.getReplyText(),
                returned.getExchange(),
                returned.getRoutingKey());
        });
        
        return rabbitTemplate;
    }
} 